////////////////////////////////////////////////
// DESCRIPTION:
//     Class for managing a Win32 file handle
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#pragma once

#include "Handle.h"

namespace FusionWare
{
    namespace Win32
    {
// @CESYSGEN IF CE_MODULES_FILESYS
        ///////////////////////////////////////////
        // Description:
        //    Class to simplify access to Win32 Files
        //
        // Comments:
        //    Destructor ensures File is always closed
        //    properly when scope containing an instance
        //    is exited
        //    Simplifies several of the APIs for Files and
        //    drivers by providing inlines with default parameters.
        //
        class File : public TWin32Handle<INVALID_HANDLE_VALUE>
        {

        public:
            File()  {};
            ~File() {};
            
            File(const File& Src) 
                : TWin32Handle<INVALID_HANDLE_VALUE>(Src)
            {
            }

            File& operator=(HANDLE h)      { TWin32Handle<INVALID_HANDLE_VALUE>::operator=(h); return *this;}
            File& operator=(const File& R) { TWin32Handle<INVALID_HANDLE_VALUE>::operator=(R); return *this;}

            // for backward compatability first 3 params remain as
            // they were when this was CDeviceDriver
            bool Open( const TCHAR* Name
                     , DWORD dwDesiredAccess=GENERIC_READ|GENERIC_WRITE
                     , DWORD dwShareMode=0
                     , DWORD Attributes=FILE_ATTRIBUTE_NORMAL
                     , DWORD Disposition=OPEN_EXISTING
                     , SECURITY_ATTRIBUTES* lpsa=NULL
                     , HANDLE Template=NULL
                     );

            DWORD Seek(LONG DistanceToMove,PLONG DistanceToMoveHigh,DWORD MoveMethod);
            bool Read( void* pBuffer
                     , DWORD NumberOfBytesToRead
                     , DWORD* pNumberOfBytesRead
                     , OVERLAPPED* pOverlapped=NULL
                     );

            bool Write( void* pBuffer
                      , DWORD nNumberOfBytesToWrite
                      , DWORD* pNumberOfBytesWritten
                      , OVERLAPPED* pOverlapped=NULL
                      );
            
            bool Read( void* pBuffer
                     , DWORD nNumberOfBytesToRead
                     , OVERLAPPED* pOverlapped=NULL
                     );

            bool Write( void* pBuffer
                      , DWORD nNumberOfBytesToWrite
                      , OVERLAPPED* pOverlapped=NULL
                      );

            bool IoControl( DWORD IoControlCode
                          , void* pInBuf
                          , DWORD InBuffSize
                          , void* pOutBuf
                          , DWORD OutBufferSize
                          , DWORD* pBytesReturned
                          , OVERLAPPED* pOverlapped=NULL
                          ) const;

            // "Put" only variation
            bool IoControl( DWORD IoControlCode
                          , void* pInBuffer
                          , DWORD nInBufferSize
                          , OVERLAPPED* pOverlapped=NULL
                          ) const;

            // "Get" only variation
            bool IoControl( DWORD IoControlCode
                          , void* pOutBuf
                          , DWORD OutBufSize
                          , DWORD* pBytesReturned
                          , OVERLAPPED* pOverlapped=NULL
                          ) const;

            // "Command" only variation
            bool IoControl(DWORD dwIoControlCode, OVERLAPPED* pOverlapped=NULL) const;

        };

        inline DWORD File::Seek( LONG DistanceToMove, LONG* DistanceToMoveHigh, DWORD MoveMethod)
        {
            SetFilePointer(this->Win32Handle, DistanceToMove, DistanceToMoveHigh, MoveMethod);
            return NO_ERROR == GetLastError();
        }

        inline bool File::Read( void* pBuffer
                              , DWORD NumberOfBytesToRead
                              , DWORD* pNumberOfBytesRead
                              , OVERLAPPED* pOverlapped/*=NULL*/
                              )
        {
            return 0!=ReadFile(this->Win32Handle, pBuffer, NumberOfBytesToRead, pNumberOfBytesRead, pOverlapped);
        }

        inline bool File::Write( void* pBuffer
                               , DWORD NumberOfBytesToWrite
                               , DWORD* pNumberOfBytesWritten
                               , OVERLAPPED* pOverlapped/*=NULL*/
                               )
        {
            return 0!=WriteFile(this->Win32Handle, pBuffer, NumberOfBytesToWrite, pNumberOfBytesWritten, pOverlapped);
        }

        inline bool File::Read( void* pBuffer
                              , DWORD NumberOfBytesToRead
                              , OVERLAPPED* pOverlapped/*=NULL*/
                              )
        {
            DWORD numRead;
            return 0!=ReadFile( this->Win32Handle
                              , pBuffer
                              , NumberOfBytesToRead
                              , &numRead
                              , pOverlapped
                              )
                     && numRead==NumberOfBytesToRead;
        }

        inline bool File::Write( void* pBuffer
                               , DWORD NumberOfBytesToWrite
                               , OVERLAPPED* pOverlapped/*=NULL*/
                               )
        {
            DWORD numWritten;
            return WriteFile( this->Win32Handle
                            , pBuffer
                            , NumberOfBytesToWrite
                            , &numWritten
                            , pOverlapped
                            )
                   && numWritten==NumberOfBytesToWrite;
        }

        inline bool File::IoControl( DWORD IoControlCode
                                   , void* pInBuf
                                   , DWORD InBufSize
                                   , void* pOutBuf
                                   , DWORD OutBufSize
                                   , DWORD* pBytesReturned
                                   , OVERLAPPED* pOverlapped/* =NULL  */
                                   ) const
        {
            return 0!=DeviceIoControl( this->Win32Handle
                                     , IoControlCode
                                     , pInBuf
                                     , InBufSize
                                     , pOutBuf
                                     , OutBufSize
                                     , pBytesReturned
                                     , pOverlapped
                                     );
        }

        inline bool File::IoControl( DWORD IoControlCode
                                   , void* pInBuf
                                   , DWORD InBufSize
                                   , OVERLAPPED* pOverlapped/* =NULL  */
                                   ) const
        {
            DWORD dwActual;
            return IoControl( IoControlCode
                            , pInBuf
                            , InBufSize
                            , NULL
                            , 0
                            , &dwActual
                            , pOverlapped
                            );
        }

        inline bool File::IoControl( DWORD IoControlCode
                                   , void* pOutBuf
                                   , DWORD OutBufSize
                                   , DWORD* pBytesReturned
                                   , OVERLAPPED* pOverlapped/* =NULL  */
                                   ) const
        {
            return IoControl( IoControlCode
                            , NULL
                            , 0
                            , pOutBuf
                            , OutBufSize
                            , pBytesReturned
                            , pOverlapped
                            );
        }

        inline bool File::IoControl(DWORD IoControlCode, OVERLAPPED* pOverlapped/* =NULL  */) const
        {
            DWORD dwActual;
            return IoControl( IoControlCode
                            , NULL
                            , 0
                            , NULL
                            , 0
                            , &dwActual
                            , pOverlapped
                            );
        }

        inline bool File::Open( const TCHAR* Name
                              , DWORD DesiredAccess/*=GENERIC_READ|GENERIC_WRITE*/
                              , DWORD ShareMode/*=0*/
                              , DWORD Attributes/*=FILE_ATTRIBUTE_NORMAL*/
                              , DWORD Disposition/*=OPEN_EXISTING*/
                              , SECURITY_ATTRIBUTES* pSA/*=NULL*/
                              , HANDLE Template/*=NULL*/
                              )
        {
            Close();
            operator=(CreateFile(Name, DesiredAccess, ShareMode, pSA, Disposition, Attributes, Template));
            return IsValid();
        }

// @CESYSGEN ENDIF CE_MODULES_FILESYS
    }
}

